package com.hsy.swu.other.game2048

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.view.animation.OvershootInterpolator
import androidx.appcompat.widget.AppCompatImageView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.internal.ViewUtils.dpToPx
import com.hsy.swu.HomeViewModel
import com.hsy.swu.R
import com.hsy.swu.clouddb.LeanCloudHelper
import com.hsy.swu.clouddb.MyUser
import com.hsy.swu.databinding.FragmentGame2048Binding
import com.hsy.swu.hsyutils.FONT
import com.hsy.swu.hsyutils.HsyFragment
import com.hsy.swu.hsyutils.MActivityUtil
import com.hsy.swu.hsyutils.MLog
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class Game2048Fragment : HsyFragment<FragmentGame2048Binding, HomeViewModel>() {
    private var isNeedRefreshRv = true

    private var isFold = false

    private var cloudDBGame2048PBSCore = 0

    override fun createViewModel(): HomeViewModel {
        return ViewModelProvider(requireActivity())[HomeViewModel::class.java]
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        mBinding.rvRank.apply {
            adapter = RankAdapter()
            layoutManager = LinearLayoutManager(requireContext())
            addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    super.onScrollStateChanged(recyclerView, newState)
                    when (newState) {
                        RecyclerView.SCROLL_STATE_DRAGGING -> {
                            game2048SlideDown()
                        }
                    }
                }
            })
        }

        mBinding.linearGame2048.setOnTouchListener { _, _ -> true }

        mBinding.game2048View.apply {
            setTypeFace(FONT)
            setRestoreOnLayoutListener {
                if (mViewModel.game2048FragmentBlockArray == null) {
                    mBinding.game2048View.initGame()
                } else {
                    mViewModel.restoreGameState(mBinding.game2048View)
                }
            }
            setScoreListener {
                mBinding.tvScore.text = "$it"
            }
            setGameOverListener {
                if (mScore > cloudDBGame2048PBSCore) {
                    updateCloudDBGame2048Score(it) {
                        refreshRvRank()
                    }
                }
                mBinding.tvScore.text = "游戏结束\n最终得分：$it"
            }
        }

        mBinding.btnStart.setOnClickListener {
            if (mBinding.game2048View.mScore > cloudDBGame2048PBSCore) {
                updateCloudDBGame2048Score(mBinding.game2048View.mScore) {
                    refreshRvRank()
                }
            }
            mBinding.game2048View.initGame()
        }

        mBinding.btnSlide.setOnClickListener {
            it as AppCompatImageView
            if (isFold) {
                game2048SlideUp()
            } else {
                game2048SlideDown()
            }
        }
    }

    override fun onResume() {
        super.onResume()
        if (isNeedRefreshRv) {
            refreshRvRank()
            isNeedRefreshRv = false
        }
    }

    override fun onPause() {
        super.onPause()

        mViewModel.storeGameState(mBinding.game2048View)
    }

    private fun getCloudDBGame2048RankList(callback: (List<RankItem>) -> Unit) {
        var rankList = mutableListOf<RankItem>()
        LeanCloudHelper.getInstance()?.findObjectInBackground(
            "MyUser",
            { query ->
                query.orderByDescending("game2048Score")
                //query.limit(20)
            }
        ) { lcObjectList ->
            lcObjectList.forEach {
                if (it.getString("game2048Score") != "0") {
                    if ((it.getString("account") ?: "") == MyUser.currentUser.account) {
                        cloudDBGame2048PBSCore = (it.getString("game2048Score") ?: "0").toInt()
                    }
                    rankList.add(
                        RankItem(
                            "1",
                            RankItem.hideName(
                                it.getString("nickName") ?: "",
                                it.getString("account") ?: ""
                            ),
                            it.getString("game2048Score").toInt(),
                        )
                    )
                }
            }
            rankList.sort()
            rankList = rankList.subList(0, 30)
            rankList.forEachIndexed { index, rankItem ->
                rankItem.rank = "${index + 1}"
            }
            callback(rankList)
        }
    }

    private fun refreshRvRank() {
        val loadingDialog = MActivityUtil.showLoading(requireContext())
        lifecycleScope.launch {
            delay(5000)
            if (loadingDialog.isShowing) {
                loadingDialog.dismiss()
                MActivityUtil.showToast("请求超时，分数无法上传")
            }
        }
        getCloudDBGame2048RankList { list ->
            (mBinding.rvRank.adapter as RankAdapter).mRankList = list

            lifecycleScope.launch {
                loadingDialog.dismiss()
            }
        }
    }

    private fun updateCloudDBGame2048Score(score: Int, callback: () -> Unit = {}) {
        LeanCloudHelper.getInstance()?.updateObjectInBackground(
            "MyUser",
            MyUser.currentUser.objectId,
            { MLog.v("更新失败，请重试") },
            { it.put("game2048Score", "$score") }
        ) {
            MLog.v("更新成功")
            callback()
        }
    }

    @SuppressLint("RestrictedApi")
    private fun game2048SlideDown() {
        if (isFold) return
        isFold = true
        mBinding.btnSlide.apply {
            animate().scaleX(0f).scaleY(0f).setDuration(0).start()
            setImageResource(R.drawable.other_page_ic_up)
            animate().scaleX(1f).scaleY(1f).setDuration(300).start()
        }
        mBinding.linearGame2048.animate()
            .translationY(mBinding.linearGame2048.height - dpToPx(requireContext(), 60))
            .setInterpolator(OvershootInterpolator())
            .setDuration(600)
            .start()
    }

    private fun game2048SlideUp() {
        if (!isFold) return
        isFold = false
        mBinding.btnSlide.apply {
            animate().scaleX(0f).scaleY(0f).setDuration(0).start()
            setImageResource(R.drawable.other_page_ic_down)
            animate().scaleX(1f).scaleY(1f).setDuration(300).start()
        }
        mBinding.linearGame2048.animate()
            .translationY(0f)
            .setInterpolator(DecelerateInterpolator())
            .setDuration(300)
            .start()
    }
}